package services

import (
	"encoding/json"
	"fmt"
	"io"
	"log"
	"net"
	"net/http"
	"net/http/httputil"
	"net/url"
	"strings"
	"sync"
	"time"
)

// DomainRouter 域名路由服务
type DomainRouter struct {
	server      *http.Server
	dnsService  *DNSPodService
	portMux     sync.RWMutex
	portMapping map[string]int // domain -> port
	running     bool
	port        int
}

// NewDomainRouter 创建域名路由器
func NewDomainRouter(port int, dnsService *DNSPodService) *DomainRouter {
	return &DomainRouter{
		dnsService:  dnsService,
		portMapping: make(map[string]int),
		port:        port,
	}
}

// Start 启动域名路由服务
func (dr *DomainRouter) Start() error {
	if dr.running {
		return fmt.Errorf("域名路由服务已在运行")
	}

	mux := http.NewServeMux()
	mux.HandleFunc("/", dr.handleRequest)

	dr.server = &http.Server{
		Addr:    fmt.Sprintf(":%d", dr.port),
		Handler: mux,
		// 🔥🔥🔥 关键修复：移除超时限制，支持大文件流式传输
		// 问题：WriteTimeout会在30秒后强制中断所有写操作，导致视频传输被cancel
		// 解决：完全移除超时限制，让流式传输自然完成
		ReadTimeout:  0,                // 无限制（读取请求头时不会太久）
		WriteTimeout: 0,                // 🚀 无限制（允许长时间流式传输，如视频、大文件下载）
		IdleTimeout:  90 * time.Second, // 保持适当的空闲超时即可
	}

	dr.running = true

	log.Printf("🌐 域名路由服务启动在端口 :%d", dr.port)

	go func() {
		if err := dr.server.ListenAndServe(); err != nil && err != http.ErrServerClosed {
			log.Printf("❌ 域名路由服务启动失败: %v", err)
			dr.running = false
		}
	}()

	return nil
}

// Stop 停止域名路由服务
func (dr *DomainRouter) Stop() error {
	if !dr.running {
		return fmt.Errorf("域名路由服务未在运行")
	}

	dr.running = false
	if dr.server != nil {
		return dr.server.Close()
	}
	return nil
}

// AddMapping 添加域名到端口的映射（如果域名已存在，则重新绑定）
func (dr *DomainRouter) AddMapping(domain string, port int) {
	dr.portMux.Lock()
	defer dr.portMux.Unlock()

	oldPort, exists := dr.portMapping[domain]
	dr.portMapping[domain] = port

	if exists && oldPort != port {
		log.Printf("🔄 重新绑定域名映射: %s -> :%d (旧端口: %d)", domain, port, oldPort)
	} else if exists {
		log.Printf("✅ 域名映射已存在，保持不变: %s -> :%d", domain, port)
	} else {
		log.Printf("📋 添加新域名映射: %s -> :%d", domain, port)
	}
}

// UpdateMapping 更新域名映射（强制更新，返回是否成功）
func (dr *DomainRouter) UpdateMapping(domain string, newPort int) bool {
	dr.portMux.Lock()
	defer dr.portMux.Unlock()

	oldPort, exists := dr.portMapping[domain]
	if !exists {
		log.Printf("⚠️  域名不存在，无法更新: %s", domain)
		return false
	}

	dr.portMapping[domain] = newPort
	log.Printf("✅ 更新域名映射: %s -> :%d (旧端口: %d)", domain, newPort, oldPort)
	return true
}

// RemoveMapping 移除域名映射
func (dr *DomainRouter) RemoveMapping(domain string) {
	dr.portMux.Lock()
	defer dr.portMux.Unlock()

	if _, exists := dr.portMapping[domain]; exists {
		delete(dr.portMapping, domain)
		log.Printf("🗑️  删除域名映射: %s", domain)
	}
}

// GetPort 根据域名获取端口
func (dr *DomainRouter) GetPort(domain string) (int, bool) {
	dr.portMux.RLock()
	defer dr.portMux.RUnlock()

	// 首先检查本地映射
	if port, exists := dr.portMapping[domain]; exists {
		return port, true
	}

	// 如果有DNSPod服务，从那里获取
	if dr.dnsService != nil {
		if port, exists := dr.dnsService.GetPortByDomain(domain); exists {
			// 缓存到本地映射
			dr.portMux.RUnlock()
			dr.portMux.Lock()
			dr.portMapping[domain] = port
			dr.portMux.Unlock()
			dr.portMux.RLock()
			return port, true
		}
	}

	return 0, false
}

// handleRequest 处理HTTP请求
func (dr *DomainRouter) handleRequest(w http.ResponseWriter, r *http.Request) {
	// 提取主机名
	host := r.Host
	if colonIndex := strings.Index(host, ":"); colonIndex != -1 {
		host = host[:colonIndex]
	}

	clientIP := getClientIP(r)
	log.Printf("📨 [域名路由] 收到请求: %s %s%s (来自: %s)", r.Method, host, r.URL.Path, clientIP)

	// 获取对应的端口
	targetPort, exists := dr.GetPort(host)
	if !exists {
		log.Printf("❌ [域名路由] 未找到域名映射: %s (当前映射数: %d)", host, len(dr.portMapping))
		log.Printf("📋 [域名路由] 当前所有域名映射:")
		dr.portMux.RLock()
		for domain, port := range dr.portMapping {
			log.Printf("   - %s -> :%d", domain, port)
		}
		dr.portMux.RUnlock()

		// 🎨 返回智能的"域名未找到"页面
		dr.sendDomainNotFoundPage(w, r, host)
		return
	}

	// 构建目标URL
	targetURL := &url.URL{
		Scheme: "http",
		Host:   fmt.Sprintf("127.0.0.1:%d", targetPort),
	}

	log.Printf("🔀 [域名路由] 代理请求: %s%s -> %s", host, r.URL.Path, targetURL.Host)

	// 创建反向代理
	proxy := httputil.NewSingleHostReverseProxy(targetURL)

	// 🔥🔥🔥 高并发优化：配置Transport支持1000+并发
	// 问题：1000并发时请求耗时8-12秒，连接池不足
	// 优化：增大连接池，缩短超时，提升吞吐量
	proxy.Transport = &http.Transport{
		MaxIdleConns:          2000,             // 🚀 2倍提升：全局最大空闲连接
		MaxIdleConnsPerHost:   2000,             // 🚀 2倍提升：每个主机的最大空闲连接
		MaxConnsPerHost:       2000,             // 🚀 2倍提升：每个主机的最大连接数
		IdleConnTimeout:       90 * time.Second, // 空闲连接超时
		TLSHandshakeTimeout:   5 * time.Second,  // 🔥 缩短TLS握手超时（快速失败）
		ExpectContinueTimeout: 1 * time.Second,
		ResponseHeaderTimeout: 60 * time.Second, // 🚀 从30秒延长至60秒（支持慢速本地服务）
		DisableKeepAlives:     false,            // 启用Keep-Alive
		ForceAttemptHTTP2:     false,            // 不强制HTTP/2
		WriteBufferSize:       64 * 1024,        // 🔥 64KB写缓冲区
		ReadBufferSize:        64 * 1024,        // 🔥 64KB读缓冲区
	}

	// 修改请求
	originalDirector := proxy.Director
	proxy.Director = func(req *http.Request) {
		originalDirector(req)
		req.Header.Set("X-Forwarded-Host", r.Host)
		req.Header.Set("X-Real-IP", clientIP)
		req.Header.Set("X-Forwarded-Proto", "http")
		req.Header.Set("X-Forwarded-For", clientIP)
	}

	// 自定义错误处理
	proxy.ErrorHandler = func(w http.ResponseWriter, r *http.Request, err error) {
		log.Printf("❌ [域名路由] 代理请求失败 [%s -> %s]: %v", host, targetURL.Host, err)
		http.Error(w, "Service Unavailable", http.StatusServiceUnavailable)
	}

	// 执行代理
	proxy.ServeHTTP(w, r)

	log.Printf("✅ [域名路由] 代理完成: %s%s -> %s", host, r.URL.Path, targetURL.Host)
}

// getClientIP 获取客户端IP地址
func getClientIP(r *http.Request) string {
	// 检查X-Forwarded-For头
	xForwardedFor := r.Header.Get("X-Forwarded-For")
	if xForwardedFor != "" {
		ips := strings.Split(xForwardedFor, ",")
		return strings.TrimSpace(ips[0])
	}

	// 检查X-Real-IP头
	xRealIP := r.Header.Get("X-Real-IP")
	if xRealIP != "" {
		return xRealIP
	}

	// 使用RemoteAddr
	ip, _, _ := net.SplitHostPort(r.RemoteAddr)
	return ip
}

// IsRunning 检查服务是否在运行
func (dr *DomainRouter) IsRunning() bool {
	return dr.running
}

// GetMappings 获取所有域名映射
func (dr *DomainRouter) GetMappings() map[string]int {
	dr.portMux.RLock()
	defer dr.portMux.RUnlock()

	mappings := make(map[string]int)
	for domain, port := range dr.portMapping {
		mappings[domain] = port
	}
	return mappings
}

// HealthCheck 健康检查
func (dr *DomainRouter) HealthCheck(domain string) error {
	port, exists := dr.GetPort(domain)
	if !exists {
		return fmt.Errorf("域名 %s 未找到对应的端口映射", domain)
	}

	// 尝试连接到目标端口
	conn, err := net.DialTimeout("tcp", fmt.Sprintf("127.0.0.1:%d", port), 5*time.Second)
	if err != nil {
		return fmt.Errorf("无法连接到端口 %d: %v", port, err)
	}
	conn.Close()

	return nil
}

// ProxyWebSocket 代理WebSocket连接
func (dr *DomainRouter) ProxyWebSocket(w http.ResponseWriter, r *http.Request, targetHost string) error {
	// 升级到WebSocket连接
	upgrader := &http.Transport{}

	// 连接到目标服务
	targetConn, err := upgrader.Dial("tcp", targetHost)
	if err != nil {
		return fmt.Errorf("连接目标服务失败: %v", err)
	}
	defer targetConn.Close()

	// 获取客户端连接
	hj, ok := w.(http.Hijacker)
	if !ok {
		return fmt.Errorf("不支持连接劫持")
	}

	clientConn, _, err := hj.Hijack()
	if err != nil {
		return fmt.Errorf("劫持连接失败: %v", err)
	}
	defer clientConn.Close()

	// 双向数据转发
	go func() {
		defer clientConn.Close()
		defer targetConn.Close()
		io.Copy(targetConn, clientConn)
	}()

	go func() {
		defer clientConn.Close()
		defer targetConn.Close()
		io.Copy(clientConn, targetConn)
	}()

	return nil
}

// GetStats 获取统计信息
func (dr *DomainRouter) GetStats() map[string]interface{} {
	dr.portMux.RLock()
	defer dr.portMux.RUnlock()

	stats := map[string]interface{}{
		"running":  dr.running,
		"port":     dr.port,
		"mappings": len(dr.portMapping),
		"domains":  make([]string, 0, len(dr.portMapping)),
	}

	for domain := range dr.portMapping {
		stats["domains"] = append(stats["domains"].([]string), domain)
	}

	return stats
}

// sendDomainNotFoundPage 发送域名未找到页面（智能判断返回JSON或HTML）
func (dr *DomainRouter) sendDomainNotFoundPage(w http.ResponseWriter, r *http.Request, domain string) {
	// 检查是否是JSON请求
	accept := r.Header.Get("Accept")
	contentType := r.Header.Get("Content-Type")
	xrw := r.Header.Get("X-Requested-With")

	isJSON := strings.Contains(accept, "application/json") ||
		strings.Contains(contentType, "application/json") ||
		xrw == "XMLHttpRequest" ||
		strings.Contains(r.URL.Path, "/api/")

	if isJSON {
		// 返回JSON响应
		w.Header().Set("Content-Type", "application/json; charset=utf-8")
		w.WriteHeader(http.StatusNotFound)

		response := map[string]interface{}{
			"success": false,
			"message": "域名未找到映射，请检查域名或在客户端建立连接",
			"code":    404,
			"status":  "not_found",
			"domain":  domain,
		}

		json.NewEncoder(w).Encode(response)
	} else {
		// 返回HTML页面
		w.Header().Set("Content-Type", "text/html; charset=utf-8")
		w.WriteHeader(http.StatusNotFound)

		html := dr.generateDomainNotFoundHTML(domain)
		w.Write([]byte(html))
	}
}

// generateDomainNotFoundHTML 生成域名未找到的HTML页面
func (dr *DomainRouter) generateDomainNotFoundHTML(domain string) string {
	return `<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>域名未找到 - Internal Net Bridge</title>
    <style>
        * {
            margin: 0;
            padding: 0;
            box-sizing: border-box;
        }
        body {
            font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;
            background-color: #ffffff;
            min-height: 100vh;
            display: flex;
            align-items: center;
            justify-content: center;
            padding: 20px;
            color: #333;
        }
        .container {
            background: white;
            border-radius: 16px;
            box-shadow: 0 10px 30px rgba(0, 0, 0, 0.08);
            max-width: 500px;
            width: 100%;
            padding: 50px 30px;
            text-align: center;
            animation: slideIn 0.5s ease-out;
            border: 1px solid #f0f0f0;
        }
        @keyframes slideIn {
            from { opacity: 0; transform: translateY(-20px); }
            to { opacity: 1; transform: translateY(0); }
        }
        .icon {
            width: 100px;
            height: 100px;
            margin: 0 auto 25px;
        }
        .icon-circle {
            width: 100%;
            height: 100%;
            border-radius: 50%;
            background: #f5f5f5;
            display: flex;
            align-items: center;
            justify-content: center;
            border: 2px solid #e0e0e0;
        }
        .icon-symbol {
            font-size: 48px;
            color: #888;
        }
        h1 {
            font-size: 28px;
            color: #333;
            margin-bottom: 12px;
            font-weight: 600;
        }
        .subtitle {
            font-size: 16px;
            color: #666;
            margin-bottom: 25px;
        }
        .domain-name {
            font-size: 18px;
            color: #333;
            font-family: 'Courier New', monospace;
            font-weight: 500;
            margin: 20px 0;
            padding: 12px;
            background: #f9f9f9;
            border-radius: 8px;
            border: 1px solid #eaeaea;
        }
        .info-box {
            background: #f8f9fa;
            border-radius: 10px;
            padding: 20px;
            margin: 25px 0;
            border-left: 3px solid #6c757d;
            text-align: left;
        }
        .info-box p {
            color: #555;
            line-height: 1.6;
            font-size: 14px;
        }
        .refresh-button {
            background: #4a5568;
            color: white;
            border: none;
            padding: 12px 36px;
            border-radius: 6px;
            font-size: 15px;
            font-weight: 500;
            cursor: pointer;
            transition: all 0.2s ease;
            margin-top: 10px;
        }
        .refresh-button:hover {
            background: #2d3748;
            transform: translateY(-1px);
        }
    </style>
</head>
<body>
    <div class="container">
        <div class="icon">
            <div class="icon-circle">
                <div class="icon-symbol">🔍</div>
            </div>
        </div>
        <h1>域名未找到</h1>
        <p class="subtitle">此域名暂未在系统中注册或隧道未连接</p>
        <div class="domain-name">` + domain + `</div>
        <div class="info-box">
            <p>
                请确认：<br>
                1. 域名拼写正确<br>
                2. 隧道服务已在客户端启动连接<br>
                3. 域名已在系统中正确配置
            </p>
        </div>
        <button class="refresh-button" onclick="window.location.reload()">刷新页面</button>
    </div>
</body>
</html>`
}
